﻿using Microsoft.Extensions.Caching.Memory;

namespace PmSoft.Cache.Abstractions;

/// <summary>
/// 运行时内存缓存实现，用于实体缓存的本地存储
/// </summary>
public class RuntimeMemoryCache : ICache
{
	private readonly IMemoryCache _cache;
	private static readonly Task CompletedTask = Task.CompletedTask;

	/// <summary>
	/// 构造函数，初始化内存缓存
	/// </summary>
	/// <param name="memoryCache">内存缓存实例</param>
	public RuntimeMemoryCache(IMemoryCache memoryCache)
	{
		_cache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache));
	}

	/// <summary>
	/// 从内存缓存获取实体（同步）
	/// </summary>
	/// <typeparam name="T">实体类型</typeparam>
	/// <param name="key">缓存键</param>
	/// <returns>缓存的实体，若不存在则返回 null</returns>
	public T? Get<T>(string key)
	{
		if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));
		return _cache.Get<T>(key.ToLower());
	}

	/// <summary>
	/// 从内存缓存获取实体（异步）
	/// </summary>
	/// <typeparam name="T">实体类型</typeparam>
	/// <param name="key">缓存键</param>
	/// <returns>缓存的实体，若不存在则返回 null</returns>
	public Task<T?> GetAsync<T>(string key)
	{
		return Task.FromResult(Get<T>(key));
	}

	/// <summary>
	/// 移除内存缓存中的实体（同步）
	/// </summary>
	/// <param name="key">缓存键</param>
	public void Remove(string key)
	{
		if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));
		_cache.Remove(key.ToLower());
	}

	/// <summary>
	/// 移除内存缓存中的实体（异步）
	/// </summary>
	/// <param name="key">缓存键</param>
	public Task RemoveAsync(string key)
	{
		Remove(key);
		return CompletedTask;
	}

	/// <summary>
	/// 设置内存缓存中的实体（同步）
	/// </summary>
	/// <typeparam name="T">实体类型</typeparam>
	/// <param name="key">缓存键</param>
	/// <param name="value">实体值</param>
	/// <param name="timeSpan">过期时间</param>
	public void Set<T>(string key, T value, TimeSpan timeSpan)
	{
		if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));
		if (value == null) throw new ArgumentNullException(nameof(value));
		_cache.Set(key.ToLower(), value, timeSpan);
	}

	/// <summary>
	/// 设置内存缓存中的实体（异步）
	/// </summary>
	/// <typeparam name="T">实体类型</typeparam>
	/// <param name="key">缓存键</param>
	/// <param name="value">实体值</param>
	/// <param name="timeSpan">过期时间</param>
	public Task SetAsync<T>(string key, T value, TimeSpan timeSpan)
	{
		Set(key, value, timeSpan);
		return CompletedTask;
	}
}